#ifndef URP_PROCEDURAL_HLSL
    #define URP_PROCEDURAL_HLSL

    #include "./SG_SUPPORT.hlsl"

    DEFINE_FLOAT(TintBlender)
    
    #if defined(BLEND_WORLD_COLOR)
        sampler2D _WorldColorTex;
        float4 _WorldRect;
        // half _TintBlender;        
        // sampler2D _WorldColorBlender;

        half4 GetWorldColor(half4 vertexColor, float3 pos)
        {
            // pos.xz = mul(unity_ObjectToWorld, v.vertex).xz;
            half4 color = tex2Dlod(_WorldColorTex, half4((pos.xz - _WorldRect.xy)/_WorldRect.zw,0,0));
            // color = lerp(color, topColor, v.color.a);
            color.a = 1 - vertexColor.a;
            return color;
        }
    #endif

    #define PROCEDURAL_FUNC ConfigureProcedural

    #if defined(UNITY_PROCEDURAL_INSTANCING_ENABLED)

        struct ProceduralInstance
        {
            #ifdef _PROCEDURAL_MATRIX
                float4x4 obj2World;
                float4x4 world2Obj;
            #else
                float4 pos; // x,y,z: pos, w:scale
                float rotation; // quaternion
            #endif
            float4 color;
        };
        
        half4 _Scale;
        StructuredBuffer<ProceduralInstance> _InstanceBuffer;
        
        void ConfigureProcedural()
        {
            ProceduralInstance data = _InstanceBuffer[unity_InstanceID];
            // unity_ObjectToWorld = data.toWorld;
            // unity_WorldToObject = data.toLocal;

            #ifdef _PROCEDURAL_MATRIX
                unity_ObjectToWorld = data.obj2World;
                unity_WorldToObject = data.world2Obj;
            #else

                half3 pos = data.pos.xyz;
                half s ; //= sin(data.rotation);
                half c ; //= cos(data.rotation);
                sincos(data.rotation, s, c);
                half3 scale = _Scale.xyz * data.pos.w;
                half3 _scale = half3(1,1,1) / scale;
                
                unity_ObjectToWorld._11_21_31_41 = float4(c*scale.x, 0, s*scale.z, 0);
                unity_ObjectToWorld._12_22_32_42 = float4(0, scale.y, 0, 0);
                unity_ObjectToWorld._13_23_33_43 = float4(-s*scale.x, 0, c*scale.z, 0);
                unity_ObjectToWorld._14_24_34_44 = float4(pos.x, pos.y, pos.z, 1);

                unity_WorldToObject._11_21_31_41 = float4(c*_scale.x, 0, -s*_scale.x, 0);
                unity_WorldToObject._12_22_32_42 = float4(0, _scale.y, 0, 0);
                unity_WorldToObject._13_23_33_43 = float4(s*_scale.z, 0, c*_scale.z, 0);
                unity_WorldToObject._14_24_34_44 = float4(-pos.x*c-pos.z*s, -pos.y, pos.x*s-pos.z*c, 1);
            #endif
        }

        #ifdef _PROCEDURAL_MATRIX
            #define INSTANCE_POSITION mul(unity_ObjectToWorld,half4(0,0,0,1)).xyz
        #else
            #define INSTANCE_POSITION _InstanceBuffer[unity_InstanceID].pos.xyz
        #endif

        #if defined(BLEND_WORLD_COLOR)
            
            #define IMPORT_PROCEDURAL(PRECISION) void Import_##PRECISION(in PRECISION##3 inPos, in PRECISION##4 inColor, out PRECISION##3 outPos, out PRECISION##4 outColor) \
            { \
                outPos = inPos; \
                outColor = GetWorldColor(inColor, INSTANCE_POSITION); \
            }

        #else
            
            #define IMPORT_PROCEDURAL(PRECISION) void Import_##PRECISION(in PRECISION##3 inPos, in PRECISION##4 inColor, out PRECISION##3 outPos, out PRECISION##4 outColor) \
            { \
                outPos = inPos; \
                outColor = PRECISION##4(1,1,1,1-inColor.a); \
            }
            

        #endif // WORLD_COLOR

        #define INSTANCED_INDIRECT_COLOR _InstanceBuffer[unity_InstanceID].color
        #define INSTANCED_INDIRECT_POS _InstanceBuffer[unity_InstanceID].pos.xyz
        
        #define GET_GRASS_COLOR(PRECISION) void GetGrassColor_##PRECISION(in PRECISION##4 IN, out PRECISION##4 OUT) \
        { \
            OUT = IN * _InstanceBuffer[unity_InstanceID].color; \
        }
        
    #else 
        #if defined(BLEND_WORLD_COLOR)
            
            #define IMPORT_PROCEDURAL(PRECISION) void Import_##PRECISION(in PRECISION##3 inPos, in PRECISION##4 inColor, out PRECISION##3 outPos, out PRECISION##4 outColor) \
            { \
                outPos = inPos; \
                outColor = GetWorldColor(inColor,mul(unity_ObjectToWorld,PRECISION##4(0,0,0,1))); \
            }

        #else
            
            #define IMPORT_PROCEDURAL(PRECISION) void Import_##PRECISION(in PRECISION##3 inPos, in PRECISION##4 inColor, out PRECISION##3 outPos, out PRECISION##4 outColor) \
            { \
                outPos = inPos; \
                outColor = PRECISION##4(1,1,1,1-inColor.a); \
            }
            
            
        #endif // WORLD_COLOR

        #define INSTANCED_INDIRECT_COLOR half4(1,1,1,1)
        #define INSTANCED_INDIRECT_POS mul(unity_ObjectToWorld,half4(0,0,0,1))
        
        #define GET_GRASS_COLOR(PRECISION) void GetGrassColor_##PRECISION(in PRECISION##4 IN, out PRECISION##4 OUT) \
        { \
            OUT = IN; \
        }

    #endif //UNITY_PROCEDURAL_INSTANCING_ENABLED

    // IMPORT_PROCEDURAL(half)
    IMPORT_PROCEDURAL(float)
    GET_GRASS_COLOR(half)
    // GET_GRASS_COLOR(float)

#endif